<?php
/**
 * View system module.
 *
 * @author Martin "DevelX" Jurča
 */
class View extends Module {
    protected $name = 'View';
    protected $administrable = true;
    protected $version = '2011-11-17';
    protected $system = true;
    protected $details = array('dependencies' => array(),
            'observes' => array('View'));

    const LABELS_TABLE = 'viewLabels';
    const MENUS_TABLE = 'viewMenus';
    const MENU_ITEMS = 'viewMenuItems';
    const PAGES_TABLE = 'viewPages';

    private $labelsTable = array('id' => "v'255'PN", 'labels' => 'TN');
    private $menusTable = array('id' => 'iPN+', 'pageId' => "v'255'IN",
            'pageUrl' => 'NT', 'area' => 's', 'lang' => "v'5'");
    private $menuItemsTable = array('id' => 'iPN+', 'parent' => 'iNI',
            'menu' => 'iNI', 'label' => 's', 'title' => "v'4096'", 'url' =>
            "v'4096'");
    private $pagesTable = array('pageId' => "v'255'IUN", 'pageUrl' =>
            "v'255'NTU", 'settings' => 'T', 'lang' => "v'4'");

    private $labelsRecord = array('table' => self::LABELS_TABLE, 'data' =>
            array());
    private $menusRecord = array('table' => self::MENUS_TABLE, 'data' =>
            array());
    private $menuItemRecord = array('table' => self::MENU_ITEMS, 'data' =>
            array());
    private $pagesRecord = array('table' => self::PAGES_TABLE, 'date' =>
            array());

    private $css = array();
    private $js = array();
    private $msgs = array(self::MSG_CONFIRM => array(), self::MSG_NOTICE =>
            array(), self::MSG_WARNING => array(), self::MSG_ERROR => array());
    private $msgsDisplayed = false;
    private $urlParts = array();
    private $displayingContent = false;
    private $displayingSubmenu = false;

    private $activeTheme = '';
    private $activeAdminTheme = 'adminiziolite';
    private $pageTitle = 'LiWeb Administration';
    private $pageKeywords = '';
    private $pageDescription = '';
    private $pageRobots = 'follow,index';
    private $pageAuthor = '';
    private $pageCopyright = '(c) 2010';
    private $pageGenerator = 'LiWeb CMS';
    private $areas = array();

    private $filesRoot;

    private $emptyPageSettings = array('theme' => '', 'title' =>'',
            'keywords' => '', 'description' => '', 'robots' => '', 'author' =>
            '', 'copyright' => '', 'generator' => '', 'areas' => array());

    private $smarty = null;
    private $unconfiguredURLParts = 0;

    const MSG_CONFIRM = 0;
    const MSG_NOTICE = 1;
    const MSG_WARNING = 2;
    const MSG_ERROR = 3;
    const MENU_ADD = 0;
    const MENU_UPDATE = 1;
    const MENU_REPLACE = 2;

    public function  __construct(DBAPI $dbapi, RecordList $recordList) {
        parent::__construct($dbapi, $recordList);
        $this->labelsRecord['properties'] = $this->labelsTable;
        $this->menusRecord['properties'] = $this->menusTable;
        $this->menuItemRecord['properties'] = $this->menuItemsTable;
        $this->pagesRecord['properties'] = $this->pagesTable;
        $this->loadSettings();
        if (Kernel::getMode() != Kernel::EVENT) {
            $this->setUpSmarty();
        }

        if (isset($_SESSION['msgs']) && is_array($_SESSION['msgs'])) {
            $this->msgs = $_SESSION['msgs'];
        }
        if (isset($_GET['url'])) {
            $this->urlParts = explode('/', $_GET['url']);
        }
    }

    public function install() {
        FTP::createFile($this->getDir('/settings', true));
        $file = @fopen($this->getDir('/settings'), 'wb');
        if (!is_resource($file)) {
            return false;
        }
        @fwrite($file, serialize(array('activeTheme' => $this->activeTheme,
                'activeAdminTheme' => $this->activeAdminTheme, 'pageTitle' =>
                $this->pageTitle, 'pageKeywords' => $this->pageKeywords,
                'pageDescription' => $this->pageDescription, 'pageRobots' =>
                $this->pageRobots, 'pageAuthor' => $this->pageAuthor,
                'pageCopyright' => $this->pageCopyright, 'pageGenerator' =>
                $this->pageGenerator, 'filesRoot' => 0)));
        $this->dbdriver->createTable(self::LABELS_TABLE, $this->labelsTable);
        $this->dbdriver->createTable(self::MENUS_TABLE, $this->menusTable);
        $this->dbdriver->createTable(self::MENU_ITEMS, $this->menuItemsTable);
        $this->dbdriver->createTable(self::PAGES_TABLE, $this->pagesTable);
        $this->createLabels();
        Modules::getModule('Users')->registerRights('View',
                $this->getRights());
        return true;
    }

    public function uninstall() {
        FTP::deleteFile($this->getDir('/settings', true));
        $this->dbdriver->dropTable(self::LABELS_TABLE);
        $this->dbdriver->dropTable(self::MENUS_TABLE);
        $this->dbdriver->dropTable(self::MENU_ITEMS);
        $this->dbdriver->dropTable(self::PAGES_TABLE);
        return true;
    }

    public function initDisplay($param = null) {
        parent::initDisplay();
        $details = $this->getUrl();
        if (count($details) == 2) {
            if ($details[1] == 'add-label') {
                $this->addJS(Config::WEB_DIR . $this->getDir('/labels.js',
                        true));
            } elseif ($details[1] == 'add-page') {
                $this->addJS(Config::WEB_DIR . $this->getDir('/pages.js',
                        true));
            }
        } elseif (count($details) == 3) {
            if ($details[1] == 'edit-label') {
                $this->addJS(Config::WEB_DIR . $this->getDir('/labels.js',
                        true));
            } elseif ($details[1] == 'edit-page') {
                $this->addJS(Config::WEB_DIR . $this->getDir('/pages.js',
                        true));
            } elseif ($details[1] == 'add-template') {
                if ($details[2] == 'html') {
                    $this->addJS(Config::WEB_DIR .
                            '/utils/tiny_mce/tiny_mce.js');
                    $this->addJS(Config::WEB_DIR . $this->getDir(
                            '/htmleditor.js', true));
                } elseif ($details[2] == 'code') {
                    $this->addJS(Config::WEB_DIR .
                            '/utils/edit_area/edit_area_full.js');
                    $this->addJS(Config::WEB_DIR . $this->getDir(
                            '/codeeditor.js', true));
                }
            }
        } elseif (count($details) == 4) {
            if ($details[1] == 'edit-template') {
                if ($details[3] == 'html') {
                    $this->addJS(Config::WEB_DIR .
                            '/utils/tiny_mce/tiny_mce.js');
                    $this->addJS(Config::WEB_DIR . $this->getDir(
                            '/htmleditor.js', true));
                } elseif ($details[3] == 'code') {
                    $this->addJS(Config::WEB_DIR .
                            '/utils/edit_area/edit_area_full.js');
                    $this->addJS(Config::WEB_DIR . $this->getDir(
                            '/codeeditor.js', true));
                }
            }
        }
    }

    public function initDisplayAdminMenuItems() {
        $this->js('/menus.js');
    }

    public function display($param = null) {
        if (Kernel::getMode() == Kernel::ADMIN) {
            if (!$this->displayingContent && ($param == null)) {
                $this->loadActiveModules();
            }
            $this->displayAdmin($param);
        } elseif (Kernel::getMode() == Kernel::DISPLAY) {
            $this->displayPublic($param);
        }
    }

    public function addCSS($url) {
        if ($url != '') {
            $this->css[] = $url;
        }
    }

    public function addJS($url) {
        if ($url != '') {
            $this->js[] = $url;
        }
    }

    public function addMessage($message, $level) {
        if (($level >= 0) && ($level <= 3) && ($message != '')) {
            $this->msgs[$level][] = $message;
            $this->msgsDisplayed = false;
        }
    }

    public function checkOverrideTemplate($module, $name, &$path) {
	$overrideTemplate = "modules/$module/templates/$name.tpl";
        if (file_exists(Config::ROOT . '/' . $overrideTemplate)) {
	    $path = $overrideTemplate;
            return true;
        }
	return false;
    }

    public function checkThemeTemplate($module, $name, &$path) {
        $themeTemplate = 'themes/' . $this->getCurrentTheme() .
		'/templates/' . $name . '.tpl';
	if (file_exists(Config::ROOT . '/' . $themeTemplate)) {
	    $path = $themeTemplate;
            return true;
        }
	return false;
    }

    public function checkDefaultTemplate($module, $name, &$path) {
	$defaultTemplate = 'themes/default/templates/' . $name . '.tpl';
        if (file_exists(Config::ROOT . '/' . $defaultTemplate)) {
	    $path = $defaultTemplate;
            return true;
        }
	return false;
    }

    public function checkTemplate($module, $name, &$path) {
	return $this->checkOverrideTemplate($module, $name, $path) || 
		$this->checkThemeTemplate($module, $name, $path) || 
		$this->checkDefaultTemplate($module, $name, $path);
    }

    public function displayTemplate($module, $name, &$params = array(),
            $convert = true) {
        if ($this->smarty == null) {
            $this->setUpSmarty();
        }
        if (Kernel::getMode() == Kernel::ADMIN) {
            $this->setMainTemplateParameters();
        }
        if ($convert) {
            $convertedParameters = &$this->convert2OutputCharset($params);
        } else {
            $convertedParameters = $params;
        }
        $this->smarty->assign($convertedParameters);
	$template = "";
        $this->checkTemplate($module, $name, $template);
        $level = error_reporting();
        $this->smarty->display($template);
        error_reporting($level);
    }

    public function &getMessages($level) {
        if (($level < 0) || ($level > 2)) {
            $level = false;
            return $level;
        }
        return $this->msgs[$level];
    }

    public function &getThemes() {
        $dir = glob(Config::ROOT . '/themes/*');
        $themes = array();
        foreach ($dir as $item) {
            if (is_dir($item)) {
                $themes[] = substr($item, strrpos($item, '/') + 1);
            }
        }
        return $themes;
    }

    public function getCurrentTheme() {
        if (Kernel::getMode() == Kernel::ADMIN) {
            return $this->activeAdminTheme;
        }
        return $this->activeTheme;
    }

    public function setCurrentTheme($theme) {
        if (Kernel::getMode() == Kernel::ADMIN) {
            $this->activeAdminTheme = $theme;
        } else {
            $this->activeTheme = $theme;
        }
    }

    public function &getAreaMenu($area) {
        // get to the URL level where menu is defined and load available langs
        $url = isset($_GET['url']) ? $_GET['url'] : '';
        $tmpUrl = $url;
        $cols = array('lang');
        $langs = array();
        while (($tmpUrl != '') || (count($langs) == 0)) {
            $pageId = sha1($tmpUrl);
            $langs = &$this->dbdriver->select(self::MENUS_TABLE, $cols,
                    "`pageId` = '$pageId' AND `area` = '" .
                    $this->dbdriver->escapeString($area). "'");
            $tmpUrl = substr($url, 0, strrpos($tmpUrl, '/'));
        }
        if (count($langs) == 0) {
            return $langs;
        }
        // choose language
        foreach ($langs as &$lang) {
            $lang = $lang['lang'];
        }
        $lang = $this->dbdriver->escapeString($this->chooseLocale($langs));
        // load menu items
        $cols = array('id');
        $menuId = &$this->dbdriver->select(self::MENUS_TABLE, $cols,
                "`pageId` = '$pageId' AND `area` = '" .
                $this->dbdriver->escapeString($area) .
                "' AND `lang` = '$lang'");
        $items = &$this->getMenu($menuId[0]['id']);
        return $items;
    }

    public function &getMenu($id, $parent = 0) {
        $cols = array('id', 'label', 'title', 'url');
        $order = array('id');
        $menu = &$this->dbdriver->select(self::MENU_ITEMS, $cols,
                "`menu` = $id AND `parent` = $parent", $order);
        foreach ($menu as &$item) {
            $item['active'] = false;
            $item['href'] = Config::WEB_DIR . $item['url'];
            $item['sub'] = &$this->getMenu($id, $item['id']);
        }
        return $menu;
    }

    public function getLang($key, $convert = false) {
        $labels = &$this->getGlobalLabels();
        if (!isset($labels[$key])) {
            return false;
        }
        if ($convert) {
            $label = &$this->convert2OutputCharset($labels[$key]);
            return $label;
        }
        return $labels[$key];
    }

    public function getUrl($howMuch = 0) {
        if (is_int($howMuch)) {
            return array_slice($this->urlParts, -$howMuch);
        } elseif ($howMuch === null) {
            return $this->unconfiguredURLParts == 0 ? array() :
                    array_slice($this->urlParts, -$this->unconfiguredURLParts);
        } else {
            return array_slice($this->urlParts, array_search($howMuch,
                    $this->urlParts));
        }
    }

    public function  __destruct() {
        if ($this->msgsDisplayed) {
            unset($_SESSION['msgs']);
        } else {
            $_SESSION['msgs'] = $this->msgs;
        }
    }

    public function &onSettings(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink());
        if (!Modules::getModule('Users')->checkRights('View',
                'edit main settings')) {
            $this->addMessage($this->lang('insufficentRights'),
                    self::MSG_ERROR);
            return $result;
        }
        $this->activeTheme = $details['publicTheme'];
        $this->activeAdminTheme = $details['adminTheme'];
        $this->pageTitle = $details['pageTitle'];
        $this->pageKeywords = $details['pageKeywords'];
        $this->pageDescription = $details['pageDescription'];
        $this->pageRobots = $details['pageRobots'];
        $this->pageAuthor = $details['pageAuthor'];
        $this->pageCopyright = $details['pageCopyright'];
        $this->pageGenerator = $details['pageGenerator'];
        $this->filesRoot = isset($details['filesRoot']) ?
                $details['filesRoot'] : 0;
        $settings = serialize(array('activeTheme' => $this->activeTheme,
                'activeAdminTheme' => $this->activeAdminTheme, 'pageTitle' =>
                $this->pageTitle, 'pageKeywords' => $this->pageKeywords,
                'pageDescription' => $this->pageDescription, 'pageRobots' =>
                $this->pageRobots, 'pageAuthor' => $this->pageAuthor,
                'pageCopyright' => $this->pageCopyright, 'pageGenerator' =>
                $this->pageGenerator, 'filesRoot' => $this->filesRoot));
        $file = @fopen($this->getDir('/settings'), 'w');
        if (!is_resource($file)) {
            return $result;
        }
        @fwrite($file, $settings);
        @fclose($file);
        return $result;
    }

    public function &onAddLabel(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink('labels/'));
        if (!Modules::getModule('Users')->checkRights('View', 'edit labels')) {
            $this->addMessage($this->lang('insufficentRights'),
                    self::MSG_ERROR);
            return $result;
        }
        $labels = array();
        if (isset($details['lang']) && is_array($details['lang'])) {
            foreach ($details['lang'] as $id => $lang) {
                $labels[$lang] = $details['label'][$id];
            }
        }
        $label = $this->labelsRecord;
        $label['data'] = array('id' => $details['id'], 'labels' =>
                serialize($labels));
        $this->dbapi->save($label);
        return $result;
    }

    public function &onEditLabel(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink());
        if (!Modules::getModule('Users')->checkRights('View', 'edit labels')) {
            $this->addMessage($this->lang('insufficentRights'),
                    self::MSG_ERROR);
            return $result;
        }
        $labels = array();
        if (isset($details['lang']) && is_array($details['lang'])) {
            foreach ($details['lang'] as $id => $lang) {
                $labels[$lang] = $details['label'][$id];
            }
        }
        $label = $this->labelsRecord;
        $label['data'] = array('id' => $details['id'], 'labels' =>
                serialize($labels));
            $this->dbapi->update($label);
        return $result;
    }

    public function &onDeleteLabel(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink());
        if (!Modules::getModule('Users')->checkRights('View', 'edit labels')) {
            $this->addMessage($this->lang('insufficentRights'),
                    self::MSG_ERROR);
            return $result;
        }
        $label = $this->labelsRecord;
        $label['data']['id'] = substr($details, 0, -1);
        $this->dbapi->delete($label);
        return $result;
    }

    public function &onAddMenu(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink());
        if (!Modules::getModule('Users')->checkRights('View',
                'edit sitemap')) {
            $this->addMessage($this->lang('insufficentRights'),
                    self::MSG_ERROR);
            return $result;
        }
        $hash = sha1($details['pageUrl']);
        $menu = $this->menusRecord;
        $menu['data'] = array(
            'pageId' => $hash,
            'pageUrl' => $details['pageUrl'],
            'area' => $details['area'],
            'lang' => $details['lang']
        );
        $this->dbapi->save($menu);
        return $result;
    }

    public function &onEditMenu(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink('menus/'));
        if (!Modules::getModule('Users')->checkRights('View',
                'edit sitemap')) {
            $this->addMessage($this->lang('insufficentRights'),
                    self::MSG_ERROR);
            return $result;
        }
        $menu = $this->menusRecord;
        $menu['data']['id'] = $details['id'];
        $this->dbapi->refresh($menu);
        $menu = $this->fillRecord($menu, $details);
        $this->dbapi->update($menu);
        return $result;
    }

    public function &onDeleteMenu(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink());
        if (!Modules::getModule('Users')->checkRights('View',
                'edit sitemap')) {
            $this->addMessage($this->lang('insufficentRights'),
                    self::MSG_ERROR);
            return $result;
        }
        $this->dbdriver->delete(self::MENUS_TABLE, '`id` = ' . (int) $details);
        $this->dbdriver->delete(self::MENU_ITEMS, '`menu` = ' .
                (int) $details);
        return $result;
    }

    public function &onAddTemplate(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink());
        if (!Modules::getModule('Users')->checkRights('View',
                'edit custom templates')) {
            $this->addMessage($this->lang('insufficentRights'),
                    self::MSG_ERROR);
            return $result;
        }
        $fileName = $details['name'] . '.' . $details['type'];
        FTP::createFile($this->getDir("/templates/custom/$fileName", true));
        $file = @fopen($this->getDir("/templates/custom/$fileName"), 'w');
        if (!is_resource($file)) {
            return $result;
        }
        @fwrite($file, $details['template']);
        @fclose($file);
        return $result;
    }

    public function &onEditTemplate(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink());
        if (!Modules::getModule('Users')->checkRights('View',
                'edit custom templates')) {
            $this->addMessage($this->lang('insufficentRights'),
                    self::MSG_ERROR);
            return $result;
        }
        $file = @fopen($this->getDir("/templates/custom/{$details['file']}"),
                'w');
        if (!is_resource($file)) {
            return $result;
        }
        @fwrite($file, $details['template']);
        @fclose($file);
        return $result;
    }

    public function &onDeleteTemplate(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink());
        if (!Modules::getModule('Users')->checkRights('View',
                'edit custom templates')) {
            $this->addMessage($this->lang('insufficentRights'),
                    self::MSG_ERROR);
            return $result;
        }
        $fname = substr($details, 0, -1);
        FTP::deleteFile($this->getDir("/templates/custom/$fname", true));
        return $result;
    }

    public function &onAddPage(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink());
        if (!Modules::getModule('Users')->checkRights('View',
                'edit page settings')) {
            $this->addMessage($this->lang('insufficentRights'),
                    self::MSG_ERROR);
            return $result;
        }
        $settings = array('theme' => $details['theme'], 'title' =>
                $details['title'], 'keywords' => $details['keywords'],
                'description' => $details['description'], 'robots' =>
                $details['robots'], 'author' => $details['author'],
                'copyright' => $details['copyright'], 'generator' =>
                $details['generator'], 'breadcrumb' => $details['breadcrumb']);
        $areas = array();
        if (isset($details['area']) && is_array($details['area'])) {
            foreach ($details['area'] as $id => $areaName) {
                $area = array();
                $usedIndexes = array();
                if (isset($details['area' . $id]) &&
                        is_array($details['area' . $id])) {
                    foreach ($details['area' . $id] as $type) {
                        $areaItem = array('type' => $type);
                        $index = isset($usedIndexes[$type]) ?
                                $usedIndexes[$type] + 1 : 0;
                        $areaItem['value'] = $details['area' . $id .
                                $type][$index];
                        if ($type == 'module') {
                            $areaItem['param'] = $details['area' . $id .
                                    'moduleParam'][$index];
                        }
                        $usedIndexes[$type] = $index;
                        if ($areaItem['value'] != '') {
                            $area[] = $areaItem;
                        }
                    }
                }
                $areas[$areaName] = $area;
            }
        }
        $settings['areas'] = $areas;
        $settings = serialize($settings);
        $page = $this->pagesRecord;
        $page['data'] = array('pageId' => sha1($details['url']), 'pageUrl' =>
                $details['url'], 'settings' => $settings, 'lang' =>
                $details['lang']);
        $this->dbapi->save($page);
        return $result;
    }

    public function &onEditPage(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink());
        if (!Modules::getModule('Users')->checkRights('View',
                'edit page settings')) {
            $this->addMessage($this->lang('insufficentRights'),
                    self::MSG_ERROR);
            return $result;
        }
        $settings = array('theme' => $details['theme'], 'title' =>
                $details['title'], 'keywords' => $details['keywords'],
                'description' => $details['description'], 'robots' =>
                $details['robots'], 'author' => $details['author'],
                'copyright' => $details['copyright'], 'generator' =>
                $details['generator'], 'breadcrumb' => $details['breadcrumb']);
        $areas = array();
        if (isset($details['area']) && is_array($details['area'])) {
            foreach ($details['area'] as $id => $areaName) {
                $area = array();
                $usedIndexes = array();
                if (isset($details['area' . $id]) &&
                        is_array($details['area' . $id])) {
                    foreach ($details['area' . $id] as $type) {
                        $areaItem = array('type' => $type);
                        $index = isset($usedIndexes[$type]) ? $usedIndexes[$type] + 1 :
                                0;
                        $areaItem['value'] = $details['area' . $id . $type][$index];
                        if ($type == 'module') {
                            $areaItem['param'] =
                                    $details['area' . $id . 'moduleParam'][$index];
                        }
                        $usedIndexes[$type] = $index;
                        if ($areaItem['value'] != '') {
                            $area[] = $areaItem;
                        }
                    }
                }
                $areas[$areaName] = $area;
            }
        }
        $settings['areas'] = $areas;
        $settings = serialize($settings);
        $page = $this->pagesRecord;
        $page['data'] = array('pageId' => sha1($details['url']), 'pageUrl' =>
                $details['url'], 'settings' => $settings, 'lang' =>
                $details['lang']);
        $this->dbapi->update($page);
        return $result;
    }

    public function &onDeletePage(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink());
        if (!Modules::getModule('Users')->checkRights('View',
                'edit page settings')) {
            $this->addMessage($this->lang('insufficentRights'),
                    self::MSG_ERROR);
            return $result;
        }
        $page = $this->pagesRecord;
        $page['data']['pageId'] = substr($details, 0, -1);
        $this->dbapi->delete($page);
        return $result;
    }

    public function onMenuItems(&$details, $source) {
        Kernel::setRedirect($this->getLink('menus/'));
        if (!$this->hasRights('edit sitemap')) {
            $this->addMessage($this->lang('insufficentRights'),
                    self::MSG_ERROR);
            return;
        }
        if (isset($details['url'])) {
            foreach ($details['url'] as $id => $url) {
                if (($url == '') && ($details['label'][$id] == '') &&
                        ($details['title'][$id] == '')) {
                    $this->dbdriver->delete(self::MENU_ITEMS, '`id` = ' .
                            (int) $id);
                } else {
                    $item = $this->menuItemRecord;
                    $item['data'] = array(
                        'id' => $id,
                        'parent' => $details['parent'],
                        'menu' => $details['menu'],
                        'label' => $details['label'][$id],
                        'title' => $details['title'][$id],
                        'url' => $url
                    );
                    $this->dbapi->update($item);
                }
            }
        }
        if (isset($details['newurl'])) {
            foreach ($details['newurl'] as $key => $url) {
                if (($url == '') && ($details['newlabel'][$key] == '') &&
                        ($details['newtitle'][$key] == '')) {
                    continue;
                }
                $item = $this->menuItemRecord;
                $item['data'] = array(
                    'parent' => $details['parent'],
                    'menu' => $details['menu'],
                    'label' => $details['newlabel'][$key],
                    'title' => $details['newtitle'][$key],
                    'url' => $url
                );
                $this->dbapi->save($item);
            }
        }
    }

    /**
     * Displays public website.
     *
     * @param mixed $param Display parameter.
     */
    private function displayPublic($param) {
        if (Kernel::isAJAXMode()) {
            if (isset($_GET['section']) &&
                    ($_GET['section'] == '-repository-')) {
                $repository = Modules::getModule('Repository');
                if ($repository == null) {
                    trigger_error('Repository module not found', E_USER_ERROR);
                } else {
                    $repository->display();
                }
            } elseif (isset($_GET['section'])) {
                $url = isset($_GET['url']) ? $_GET['url'] : '';
                $settings = &$this->loadPublicPageSettings($url);
                $this->activeTheme = $settings['theme'];
                $this->areas = $settings['areas'];
                if ($this->smarty == null) {
                    $this->setUpSmarty();
                }
                $this->loadActivePublicModules();
                $this->setPublicHeadParameters($settings);
                $this->displayPublicArea($this->areas[$_GET['section']],
                        $_GET['section']);
            }
        } elseif ($param == null) {
            $url = isset($_GET['url']) ? $_GET['url'] : '';
            if ($url == '404') {
                header("HTTP/1.0 404 Not Found");
            } elseif ($url == '403') {
                header("HTTP/1.0 403 Forbidden Explained");
            }
            $settings = &$this->loadPublicPageSettings($url);
            $this->activeTheme = $settings['theme'];
            $this->areas = $settings['areas'];
            if ($this->smarty == null) {
                $this->setUpSmarty();
            }
            $this->loadActivePublicModules();
            $this->setPublicHeadParameters($settings);
            $this->template('page');
        } else {
            if (isset($this->areas[$param])) {
                $this->displayPublicArea($this->areas[$param], $param);
            } elseif ($param == '-breadcrumb-') {
                $this->displayPublicBreadcrumb();
            } else {
                trigger_error("Area $param is not defined", E_USER_WARNING);
            }
        }
    }

    private function displayPublicBreadcrumb() {
        $url = $this->getURL();
        $links = array();
        $last = -1;
        while (count($url) > 0) {
            $urlStr = implode('/', $url);
            $settings = &$this->loadPublicPageSettings($urlStr);
            if (($last < 0) || (($settings['title'] != '') &&
                    ($links[$last]['label'] != $settings['title']))) {
                $link = array('href' => Config::WEB_DIR . "/$urlStr/",
                        'label' => $settings['title'], 'title' =>
                        $settings['description']);
                if (isset($settings['breadcrumb']) &&
                        ($settings['breadcrumb'] != '')) {
                    $link['label'] = $settings['breadcrumb'];
                }
                $links[] = $link;
                $last++;
            }
            $url = array_slice($url, 0, -1);
        }
        $settings = &$this->loadPublicPageSettings('');
        $link = array('href' => Config::WEB_DIR . '/',
                'label' => $settings['title'], 'title' =>
                $settings['description']);
        if ($settings['breadcrumb'] != '') {
            $link['label'] = $settings['breadcrumb'];
        }
        $links[] = $link;
        $links = array_reverse($links);
        $params = array('links' => $links);
        $this->template('breadcrumb', $params);
    }

    /**
     * Loads and inits modules to display.
     *
     */
    private function loadActivePublicModules() {
        $loaded = array();
        foreach ($this->areas as $area) {
            foreach ($area as $item) {
                if (($item['type'] == 'module') && !isset($loaded[
                        $item['value'] . '-' . $item['param']])) {
                    $module = Modules::getModule($item['value']);
                    if ($module != null) {
                        $module->initDisplay($item['param']);
                    }
                    $loaded[$item['value'] . $item['param']] = true;
                }
            }
        }
        $this->smarty->assign('css', $this->css);
        $this->smarty->assign('js', $this->js);
    }

    /**
     * Displays public area according to provided settings.
     *
     * @param Array $area Area settings.
     * @param String $areaName name of area to display.
     */
    private function displayPublicArea(&$area, $areaName) {
        foreach ($area as &$item) {
            if ($item['type'] == 'label') {
                echo iconv('utf-8', Kernel::getCharset() . '//TRANSLIT',
                        $this->getLang($item['value']));
            } elseif ($item['type'] == 'template') {
                $type = substr($item['value'], strrpos($item['value'], '.') +
                        1);
                if ($type == 'html') {
                    $content = @file_get_contents($this->getDir(
                            "/templates/custom/{$item['value']}"));
                    echo iconv('utf-8', Kernel::getCharset() . '//TRANSLIT',
                            $content);
                } elseif ($type == 'php') {
                    $content = @file_get_contents($this->getDir(
                            "/templates/custom/{$item['value']}"));
                    $content = iconv('utf-8', Kernel::getCharset() .
                            '//TRANSLIT', $content);
                    eval ("?>$content");
                } elseif ($type == 'tpl') {
                    $content = @file_get_contents($this->getDir(
                            "/templates/custom/{$item['value']}"));
                    $params = array('customTemplate' => $content);
                    $this->template('customtemplate', $params);
                }
            } elseif ($item['type'] == 'menu') {
                $menu = &$this->getAreaMenu($areaName);
                $params = array('menu' => $menu);
		$this->templateOverrideChain(array("$areaName-menu",
                        'mainmenu'), $params);
            } else {
                $module = Modules::getModule($item['value']);
                if ($module == null) {
                    trigger_error("Module $module is not available",
                            E_USER_WARNING);
                } else {
                    $module->display($item['param']);
                }
            }
        }
    }

    /**
     * Sets smarty parameters for main template tags within the tag head.
     *
     * @param Array $settings Page settings.
     */
    private function setPublicHeadParameters(&$settings) {
        $this->smarty->assign('css', $this->css);
        $this->smarty->assign('js', $this->js);
        $this->smarty->assign('themeRoot', Config::WEB_DIR . '/themes/' .
                $this->getCurrentTheme());
        $this->smarty->assign('webRoot', Config::WEB_DIR);
        $this->smarty->assign('pageTitle', iconv('utf-8',
                Kernel::getCharset() . '//TRANSLIT', $settings['title']));
        $this->smarty->assign('pageKeywords', iconv('utf-8',
                Kernel::getCharset() . '//TRANSLIT', $settings['keywords']));
        $this->smarty->assign('pageDescription', iconv('utf-8', Kernel::
                getCharset() . '//TRANSLIT', $settings['description']));
        $this->smarty->assign('pageRobots', iconv('utf-8',
                Kernel::getCharset() . '//TRANSLIT', $settings['robots']));
        $this->smarty->assign('pageAuthor', iconv('utf-8',
                Kernel::getCharset() . '//TRANSLIT', $settings['author']));
        $this->smarty->assign('pageCharset', Kernel::getCharset());
        $this->smarty->assign('pageLanguage', Kernel::getLanguage());
        $this->smarty->assign('pageCopyright', iconv('utf-8',
                Kernel::getCharset(), $settings['copyright']));
        $this->smarty->assign('pageGenerator', iconv('utf-8',
                Kernel::getCharset() . '//TRANSLIT', $settings['generator']));
        $msgs = &$this->convert2OutputCharset($this->msgs[self::MSG_ERROR]);
        $this->smarty->assign('errors', $msgs);
        $msgs = &$this->convert2OutputCharset($this->msgs[self::MSG_WARNING]);
        $this->smarty->assign('warnings', $msgs);
        $msgs = &$this->convert2OutputCharset($this->msgs[self::MSG_NOTICE]);
        $this->smarty->assign('notices', $msgs);
        $msgs = &$this->convert2OutputCharset($this->msgs[self::MSG_CONFIRM]);
        $this->smarty->assign('confirms', $msgs);
        $this->msgsDisplayed = true;
    }

    /**
     * Returns page settings for given page url. The settings array is returned
     * by pointer.
     *
     * @param String $url Public page URL.
     * @return Array Page settings.
     */
    private function &loadPublicPageSettings($url, $fill = true) {
        $settings = $this->pagesRecord;
        $settings['data']['pageId'] = sha1($url);
        $this->dbapi->refresh($settings);
        if (!is_array($settings)) {
            $this->unconfiguredURLParts++;
            $settings = $this->emptyPageSettings;
        } else {
            $settings = unserialize($settings['data']['settings']);
        }
        if (strlen($url) > 0) {
            $subpageSettings = &$this->loadPublicPageSettings(substr($url,
                    0, strrpos($url, '/')), false);
            $this->fillBlankPageSettingsFiels($settings, $subpageSettings);
        }
        $this->fillBlankPageSettingsFilesWithDefaults($settings);
        if ($fill) {
            foreach ($settings as $key => &$property) {
                if (is_string($property) &&
                        preg_match('/^[{].+[}]$/', $property)) {
                    $module = preg_replace('/^[{](.+)[}]$/', '\\1', $property);
                    $module = Modules::getModule($module);
                    if ($module) {
                        $property = $module->getMetaInfo($key, $url);
                    }
                }
            }
        }
        return $settings;
    }

    /**
     * Fills empty fields in page settings array using default settings values.
     *
     * @param Array $settings Page settings
     */
    private function fillBlankPageSettingsFilesWithDefaults(&$settings) {
        $objectProperties = array('theme' => 'activeTheme', 'title' =>
                'pageTitle', 'keywords' => 'pageKeywords', 'description' =>
                'pageDescription', 'robots' => 'pageRobots', 'author' =>
                'pageAuthor', 'copyright' => 'pageCopyright', 'generator' =>
                'pageGenerator');
        foreach ($settings as $property => $value) {
            if (($value == '') && isset($objectProperties[$property]) &&
                    isset($this->{$objectProperties[$property]})) {
                $settings[$property] = $this->{$objectProperties[$property]};
            }
        }
    }

    /**
     * Fills the missing page settings fields using values provided by subpage
     * settings.
     *
     * @param Array $settings Page settings
     * @param Array $subpage Subpage settings (subpage as closer to doc. root)
     */
    private function fillBlankPageSettingsFiels(&$settings, &$subpage) {
        foreach ($settings as $key => $value) {
            if ($value == '') {
                $settings[$key] = $subpage[$key];
            }
        }
        foreach ($subpage['areas'] as $name => $areaSettings) {
            if (!isset($settings['areas'][$name])) {
                $settings['areas'][$name] = $areaSettings;
            }
        }
    }

    /**
     * Sets template parameters for SMARTY
     *
     */
    private function setMainTemplateParameters() {
        $labels = &$this->getGlobalLabels();
        $this->smarty->assign($labels);
        $this->smarty->assign('css', $this->css);
        $this->smarty->assign('js', $this->js);
        $this->smarty->assign('themeRoot', Config::WEB_DIR . '/themes/' .
                $this->getCurrentTheme());
        $this->smarty->assign('webRoot', Config::WEB_DIR);
        $this->smarty->assign('pageTitle', iconv('utf-8',
                Kernel::getCharset() . '//TRANSLIT', $this->pageTitle));
        $this->smarty->assign('pageKeywords', iconv('utf-8',
                Kernel::getCharset() . '//TRANSLIT', $this->pageKeywords));
        $this->smarty->assign('pageDescription', iconv('utf-8',
                Kernel::getCharset() . '//TRANSLIT', $this->pageDescription));
        $this->smarty->assign('pageRobots', iconv('utf-8',
                Kernel::getCharset() . '//TRANSLIT', $this->pageRobots));
        $this->smarty->assign('pageAuthor', iconv('utf-8',
                Kernel::getCharset() . '//TRANSLIT', $this->pageAuthor));
        $this->smarty->assign('pageCharset', Kernel::getCharset());
        $this->smarty->assign('pageLanguage', Kernel::getLanguage());
        $this->smarty->assign('pageCopyright', iconv('utf-8',
                Kernel::getCharset() . '//TRANSLIT', $this->pageCopyright));
        $this->smarty->assign('pageGenerator', iconv('utf-8',
                Kernel::getCharset() . '//TRANSLIT', $this->pageGenerator));
        $msgs = &$this->convert2OutputCharset($this->msgs[self::MSG_ERROR]);
        $this->smarty->assign('errors', $msgs);
        $msgs = &$this->convert2OutputCharset($this->msgs[self::MSG_WARNING]);
        $this->smarty->assign('warnings', $msgs);
        $msgs = &$this->convert2OutputCharset($this->msgs[self::MSG_NOTICE]);
        $this->smarty->assign('notices', $msgs);
        $msgs = &$this->convert2OutputCharset($this->msgs[self::MSG_CONFIRM]);
        $this->smarty->assign('confirms', $msgs);
        $this->msgsDisplayed = true;
    }

    /**
     * Converts array of strings or string to system output charset. The method
     * preserves uuncovertable values.
     *
     * @param mixed $input Array or string to convert.
     * @return mixed Converted array or string.
     */
    private function &convert2OutputCharset(&$input) {
        if ((Kernel::getCharset() == 'utf-8') ||
                (strtolower(Kernel::getCharset()) == 'utf-8')) {
            return $input;
        }
        if (is_array($input)) {
            $result = array();
            foreach ($input as $key => $value) {
                $result[$key] = &$this->convert2OutputCharset($value);
            }
        } elseif (is_string($input)) {
            $result = iconv('utf-8', Kernel::getCharset() . '//TRANSLIT',
                    $input);
        } else {
            $result = $input;
        }
        return $result;
    }

    /**
     * Displays module admin interface.
     *
     */
    private function displayModuleAdmin() {
        if (!Modules::getModule('Users')->checkRights('View', 'view admin')) {
            return;
        }
        $details = $this->getUrl();
        if (count($details) == 2) {
            if ($details[1] == 'settings') {
                $this->displayAdminSettings();
            } elseif ($details[1] == 'labels') {
                $this->displayAdminLabels();
            } elseif ($details[1] == 'add-label') {
                $this->displayAdminAddLabel();
            } elseif ($details[1] == 'menus') {
                $this->displayAdminMenus();
            } elseif ($details[1] == 'add-menu') {
                $this->displayAdminAddMenu();
            } elseif ($details[1] == 'custom-templates') {
                $this->displayAdminCustomTemplates();
            } elseif ($details[1] == 'add-page') {
                $this->displayAdminAddPage();
            }
        } elseif (count($details) == 3) {
            if ($details[1] == 'edit-label') {
                $this->displayAdminEditLabel($details[2]);
            } elseif ($details[1] == 'add-template') {
                $this->displayAdminAddTemplate();
            } elseif ($details[1] == 'edit-page') {
                $this->displayAdminEditPage($details[2]);
            } elseif ($details[1] == 'edit-menu') {
                $this->displayAdminEditMenu($details[2]);
            } elseif ($details[1] == 'menu-items') {
                $this->displayAdminMenuItems($details[2]);
            }
        } elseif (count($details) == 4) {
            if ($details[1] == 'edit-template') {
                $this->displayAdminEditTemplate($details[2]);
            } elseif ($details[1] == 'menu-items') {
                $this->displayAdminMenuItems($details[2], $details[3]);
            }
        } elseif (count($details) == 1) {
            $this->displayAdminPages();
        }
    }

    /**
     * Displays administration interface for editing page settings.
     *
     * @param String $pageId ID string of page to edit.
     */
    private function displayAdminEditPage($pageId) {
        if (!Modules::getModule('Users')->checkRights('View',
                'edit page settings')) {
            return;
        }
        $themes = &$this->getThemes();
        $labels = &$this->getGlobalLabels();
        $templates = glob($this->getDir('/templates/custom/*'));
        $templates = $templates ? $templates : array();
        foreach ($templates as &$template) {
            $template = substr($template, strrpos($template, '/') + 1);
        }
        $modules = Modules::getModuleList();
        $moduleLabels = array();
        foreach ($modules as $module) {
            $moduleInstance = Modules::getModule($module);
            if ($moduleInstance) {
                $moduleLabels[] = $moduleInstance->getUIName();
            } else {
                $moduleLabels[] = $module;
            }
        }
        $page = $this->pagesRecord;
        $page['data']['pageId'] = $pageId;
        $this->dbapi->refresh($page);
        $page['data']['settings'] = unserialize($page['data']['settings']);
        $params = array('formStart' => $this->getForm('editPage', true,
                'View'), 'addPageForm' => $this->lang('addPageForm'),
                'themeLabel' => $this->lang('themeLabel'), 'default' =>
                $this->lang('default'), 'titleLabel' => $this->lang(
                'titleLabel'), 'keywordsLabel' => $this->lang('keywordsLabel'),
                'descriptionLabel' => $this->lang('descriptionLabel'),
                'robotsLabel' => $this->lang('robotsLabel'), 'authorLabel' =>
                $this->lang('authorLabel'), 'copyrightLabel' => $this->lang(
                'copyrightLabel'), 'generatorLabel' => $this->lang(
                'generatorLabel'), 'areasLabel' => $this->lang('areasLabel'),
                'addRow' => $this->lang('addRow'), 'save' => $this->lang(
                'save'), 'themes' => $themes, 'urlLabel' => $this->lang(
                'urlLabel'), 'areaNameLabel' => $this->lang('areaNameLabel'),
                'addGlobalLabel' => $this->lang('addGlobalLabel'), 'labels' =>
                $labels, 'templates' => $templates, 'modules' => $modules,
                'addMenuLabel' => $this->lang('addMenuLabel'),
                'addTemplateLabel' => $this->lang('addTemplateLabel'),
                'addModuleLabel' => $this->lang('addModuleLabel'),
                'displayModuleLabel' => $this->lang('displayModuleLabel'),
                'displayTemplateLabel' => $this->lang('displayTemplateLabel'),
                'displayMenuLabel' => $this->lang('displayMenuLabel'),
                'displayLabelLabel' => $this->lang('displayLabelLabel'),
                'moduleParamsLabel' => $this->lang('moduleParamsLabel'),
                'pageLanguageLabel' => $this->lang('pageLanguageLabel'),
                'page' => $page['data'], 'numAreas' =>
                count($page['data']['settings']['areas']), 'sections' =>
                $this->getThemeSections($page['data']['settings']['theme'] !=
                '' ? $page['data']['settings']['theme'] : $this->activeTheme),
                'moduleLabels' => $moduleLabels);
        $this->template('editpage', $params);
    }

    /**
     * Displays administration interface for adding page configuration.
     *
     */
    private function displayAdminAddPage() {
        if (!Modules::getModule('Users')->checkRights('View',
                'edit page settings')) {
            return;
        }
        $themes = &$this->getThemes();
        $labels = &$this->getGlobalLabels();
        $templates = glob($this->getDir('/templates/custom/*'));
        $templates = $templates ? $templates : array();
        foreach ($templates as &$template) {
            $template = substr($template, strrpos($template, '/') + 1);
        }
        $modules = Modules::getModuleList();
        $moduleLabels = array();
        foreach ($modules as $module) {
            $moduleInstance = Modules::getModule($module);
            if ($moduleInstance) {
                $moduleLabels[] = $moduleInstance->getUIName();
            } else {
                $moduleLabels[] = $module;
            }
        }
        $params = array('formStart' => $this->getForm('addPage', true, 'View'),
                'addPageForm' => $this->lang('addPageForm'), 'themeLabel' =>
                $this->lang('themeLabel'), 'default' => $this->lang('default'),
                'titleLabel' => $this->lang('titleLabel'), 'keywordsLabel' =>
                $this->lang('keywordsLabel'), 'descriptionLabel' =>
                $this->lang('descriptionLabel'), 'robotsLabel' => $this->lang(
                'robotsLabel'), 'authorLabel' => $this->lang('authorLabel'),
                'copyrightLabel' => $this->lang('copyrightLabel'),
                'generatorLabel' => $this->lang('generatorLabel'),
                'areasLabel' => $this->lang('areasLabel'), 'addRow' =>
                $this->lang('addRow'), 'create' => $this->lang('create'),
                'themes' => $themes, 'urlLabel' => $this->lang('urlLabel'),
                'areaNameLabel' => $this->lang('areaNameLabel'),
                'addGlobalLabel' => $this->lang('addGlobalLabel'), 'labels' =>
                $labels, 'templates' => $templates, 'modules' => $modules,
                'addMenuLabel' => $this->lang('addMenuLabel'),
                'addTemplateLabel' => $this->lang('addTemplateLabel'),
                'addModuleLabel' => $this->lang('addModuleLabel'),
                'displayModuleLabel' => $this->lang('displayModuleLabel'),
                'displayTemplateLabel' => $this->lang('displayTemplateLabel'),
                'displayMenuLabel' => $this->lang('displayMenuLabel'),
                'displayLabelLabel' => $this->lang('displayLabelLabel'),
                'moduleParamsLabel' => $this->lang('moduleParamsLabel'),
                'pageLanguageLabel' => $this->lang('pageLanguageLabel'),
                'sections' => $this->getThemeSections($this->activeTheme),
                'moduleLabels' => $moduleLabels);
        $this->template('addpage', $params);
    }

    /**
     * Loads root of the tree of public pages for administration purposes
     *
     * @return Array List of pages ordered according to the navigation tree
     */
    private function loadPagesTreeRoot() {
        $cols = array();
        $pages = &$this->dbdriver->select(self::PAGES_TABLE, $cols,
               "`pageUrl` = ''");
        foreach ($pages as &$page) {
            $page['settings'] = unserialize($page['settings']);
            $page['index'] = '.';
            $page['edit'] = $this->getLink("edit-page/{$page['pageId']}/");
            $page['delete'] = $this->getLink("{$page['pageId']}/",
                   'deletePage');
        }
        $subpages = $this->loadPagesTree('');
        return array_merge($pages, $subpages);
    }

    private function &loadPagesTreeSubpages(&$filteredPages, $index) {
        $pages = array();
        $i = 1;
        foreach ($filteredPages as $page) {
            $pages[] = $page;
            $pages = array_merge($pages, $this->loadPagesTree(
                    $page['pageUrl'], "$index.$i"));
            $i++;
        }
        return $pages;
    }

    /**
     * Loads tree of public pages for administration purposes
     *
     * @return Array List of pages ordered according to the navigation tree
     */
    private function loadPagesTree($prefix = null, $index = '') {
        $cols = array();
        $orderBy = array('pageUrl');
        if ($prefix === null) {
            return $this->loadPagesTreeRoot();
        } else {
            $prefixLength = strlen($prefix);
            $pages = &$this->dbdriver->select(self::PAGES_TABLE, $cols,
                    "`pageUrl` LIKE '" .
                    $this->dbdriver->escapeString($prefix) .
                    ($prefix != '' ? '/' : '') . "%' AND `pageUrl` != ''",
                    $orderBy);
            $filteredPages = array();
            $i = 1;
            foreach ($pages as &$page) {
                $page['settings'] = unserialize($page['settings']);
                $page['index'] = "$index.$i";
                $page['edit'] = $this->getLink("edit-page/{$page['pageId']}/");
                $page['delete'] = $this->getLink("{$page['pageId']}/",
                        'deletePage');
                if (strpos(substr($page['pageUrl'], $prefixLength + 1),
                        '/') === false) {
                    $filteredPages[] = $page;
                    $i++;
                }
            }
            if ($i == 1) {
                $filteredPages = $pages;
            }
            $pages = &$this->loadPagesTreeSubpages($filteredPages, $index);
            return $pages;
        }
    }

    /**
     * Displays administration interface for adding new page settings.
     *
     */
    private function displayAdminPages() {
        if (!Modules::getModule('Users')->checkRights('View',
                'edit page settings')) {
            return;
        }
        $pages = $this->loadPagesTree();
        $params = array('pagesTable' => $this->lang('pagesTable'), 'url' =>
                $this->lang('url'), 'lang' => $this->lang('pageLang'),
                'options' => $this->lang('options'), 'edit' => $this->lang(
                'edit'), 'delete' => $this->lang('delete'), 'addPage' =>
                $this->lang('addPage'), 'addPageTitle' => $this->lang(
                'addPageTitle'), 'addPageLink' => $this->getLink('add-page/'),
                'pages' => $pages);
        $this->template('pages', $params);
    }

    /**
     * Displays administration interface for editing custom templates.
     *
     */
    private function displayAdminEditTemplate($template) {
        if (!Modules::getModule('Users')->checkRights('View',
                'edit custom templates')) {
            return;
        }
        $params = array('formStart' => $this->getForm('editTemplate', true,
                'View'), 'editTemplateForm' => $this->lang('editTemplateForm'),
                'templateName' => $this->lang('templateName'),
                'templateType' => $this->lang('templateType'), 'save' =>
                $this->lang('save'), 'name' => pathinfo($template,
                PATHINFO_FILENAME), 'type' => pathinfo($template,
                PATHINFO_EXTENSION), 'file' => $template, 'template' =>
                file_get_contents($this->getDir(
                "/templates/custom/$template")), 'fileCategoryId' =>
                $this->filesRoot);
        $this->template('edittemplate', $params);
    }

    /**
     * Displays administration interface for adding new custom template.
     *
     */
    private function displayAdminAddTemplate() {
        if (!Modules::getModule('Users')->checkRights('View',
                'edit custom templates')) {
            return;
        }
        $params = array('formStart' => $this->getForm('addTemplate', true,
                'View'), 'addTemplateForm' => $this->lang('addTemplateForm'),
                'templateName' => $this->lang('templateName'),
                'templateType' => $this->lang('templateType'), 'create' =>
                $this->lang('create'), 'fileCategoryId' => $this->filesRoot);
        $this->template('addtemplate', $params);
    }

    /**
     * Displays administration interface for managing custom templates.
     *
     */
    private function displayAdminCustomTemplates() {
        if (!Modules::getModule('Users')->checkRights('View',
                'edit custom templates')) {
            return;
        }
        $templates = glob($this->getDir('/templates/custom/*'));
        $templates = $templates ? $templates : array();
        foreach ($templates as &$template) {
            $fname = substr($template, strrpos($template, '/') + 1);
            $template = array('name' => pathinfo($fname, PATHINFO_FILENAME),
                    'type' => pathinfo($fname, PATHINFO_EXTENSION));
            $template['editText'] = $this->getLink(
                    "edit-template/$fname/text/");
            $template['editCode'] = $this->getLink(
                    "edit-template/$fname/code/");
            $template['editHtml'] = $this->getLink(
                    "edit-template/$fname/html/");
            $template['delete'] = $this->getLink("$fname/", 'deleteTemplate');
        }
        $params = array('customTemplates' => $this->lang(
                'customTemplatesTable'), 'addNewTemplate' => $this->lang(
                'addNewTemplate'), 'textEditorLink' => $this->getLink(
                'add-template/text/'), 'textEditorTitle' => $this->lang(
                'textEditorTitle'), 'textEditor' => $this->lang('textEditor'),
                'htmlEditorLink' => $this->getLink('add-template/html/'),
                'htmlEditorTitle' => $this->lang('htmlEditorTitle'),
                'htmlEditor' => $this->lang('htmlEditor'), 'codeEditorLink' =>
                $this->getLink('add-template/code/'), 'codeEditorTitle' =>
                $this->lang('codeEditorTitle'), 'codeEditor' =>
                $this->lang('codeEditor'), 'name' => $this->lang('name'),
                'type' => $this->lang('type'), 'options' =>
                $this->lang('options'), 'templates' => $templates,
                'editText' => $this->lang('editText'), 'editCode' =>
                $this->lang('editCode'), 'editHtml' => $this->lang('editHtml'),
                'delete' => $this->lang('delete'));
        $this->template('custom', $params);
    }

    private function displayAdminMenuItems($menuId, $parent = 0) {
        $cols = array('id', 'label', 'title', 'url');
        $order = array('id');
        $items = &$this->dbdriver->select(self::MENU_ITEMS, $cols,
                "`menu` = $menuId AND `parent` = $parent", $order);
        foreach ($items as &$item) {
            $item['sub'] = $this->getLink("menu-items/$menuId/{$item['id']}/");
        }
        $params = array('items' => &$items, 'formStart' =>
                $this->getForm('menuItems', true, 'View'), 'menu' => $menuId,
                'parent' => $parent);
        $this->template('menuitems', $params);
    }

    /**
     * Displays administration interface for editing menus.
     *
     * @param String $pageId PageId hash of page URL to which is the menu
     *        attached.
     * @param String $area Area where the menu should be displayed.
     * @param String $lang Language code of menu.
     */
    private function displayAdminEditMenu($id) {
        $cols = array('id', 'pageUrl', 'area', 'lang');
        $menu = &$this->dbdriver->select(self::MENUS_TABLE, $cols, '`id` = ' .
                $id);
        if (!isset($menu[0])) {
            return;
        }
        $menu[0]['formStart'] = $this->getForm('editMenu', true, 'View');
        $this->template('editmenu', $menu[0]);
    }

    /**
     * Displays administration interface for adding menus.
     *
     */
    private function displayAdminAddMenu() {
        if (!Modules::getModule('Users')->checkRights('View',
                'edit sitemap')) {
            return;
        }
        $params = array('formStart' => $this->getForm('addMenu', true, 'View'),
                'addMenuForm' => $this->lang('addMenuForm'), 'pageUrlLabel' =>
                $this->lang('pageUrlLabel'), 'areaLabel' =>
                $this->lang('areaLabel'), 'langLabel' =>
                $this->lang('langLabel'), 'create' => $this->lang('create'),
                'menuItemsTable' => $this->lang('menuItemsTable'), 'url' =>
                $this->lang('url'), 'label' => $this->lang('label'), 'title' =>
                $this->lang('title'), 'addMenuItem' =>
                $this->lang('addMenuItem'));
        $this->template('addmenu', $params);
    }

    /**
     * Displays administration interface for managing menus.
     *
     */
    private function displayAdminMenus() {
        if (!Modules::getModule('Users')->checkRights('View',
                'edit sitemap')) {
            return;
        }
        $columns = array('pageUrl', 'area', 'lang', 'id');
        $menus = &$this->dbdriver->select(self::MENUS_TABLE, $columns);
        foreach ($menus as &$menu) {
            $menu['edit'] = $this->getLink("edit-menu/{$menu['id']}/");
            $menu['items'] = $this->getLink("menu-items/{$menu['id']}/");
            $menu['delete'] = $this->getLink($menu['id'], 'deleteMenu');
        }
        $params = array('addMenuLink' => $this->getLink('add-menu/'),
                'menus' => $menus);
        $this->template('menus', $params);
    }

    /**
     * Displays administration interface for edditing gloval localized labels.
     *
     * @param String $id Label ID string.
     */
    private function displayAdminEditLabel($id) {
        if (!Modules::getModule('Users')->checkRights('View', 'edit labels')) {
            return;
        }
        $label = $this->labelsRecord;
        $label['data']['id'] = $id;
        $this->dbapi->refresh($label);
        $label = $label['data'];
        $label['labels'] = unserialize($label['labels']);
        foreach ($label['labels'] as &$lbl) {
            $lbl = htmlspecialchars($lbl);
        }
        $params = array('formStart' => $this->getForm('editLabel', true,
                'View'), 'editLabelForm' => $this->lang('editLabelForm'),
                'idLabel' => $this->lang('idLabel'), 'languageCode' =>
                $this->lang('languageCode'), 'localLabel' => $this->lang(
                'localLabel'), 'addTranslation' => $this->lang(
                'addTranslation'), 'create' => $this->lang('save'), 'id' =>
                $label['id'], 'labels' => $label['labels']);
        $this->template('editlabel', $params);
    }

    /**
     * Displays administration interface for adding new global localized label.
     *
     */
    private function displayAdminAddLabel() {
        if (!Modules::getModule('Users')->checkRights('View', 'edit labels')) {
            return;
        }
        $params = array('formStart' => $this->getForm('addLabel', true,
                'View'), 'addLabelForm' => $this->lang('addLabelForm'),
                'idLabel' => $this->lang('idLabel'), 'languageCode' =>
                $this->lang('languageCode'), 'localLabel' => $this->lang(
                'localLabel'), 'addTranslation' => $this->lang(
                'addTranslation'), 'create' => $this->lang('create'));
        $this->template('addlabel', $params);
    }

    /**
     * Displays administration interface for editing global localized labels.
     *
     */
    private function displayAdminLabels() {
        if (!Modules::getModule('Users')->checkRights('View', 'edit labels')) {
            return;
        }
        $labels = &$this->dbapi->load($this->labelsRecord);
        foreach ($labels as &$label) {
            $label = $label['data'];
            $label['labels'] = unserialize($label['labels']);
            if (isset($label['labels'][Kernel::getLanguage()])) {
                $label['labels'] = $label['labels'][Kernel::getLanguage()];
            } elseif (isset($label['labels'][Config::DEFAULT_LANG])) {
                $label['labels'] = $label['labels'][Config::DEFAULT_LANG];
            } else {
                $keys = array_keys($label['labels']);
                $label['labels'] = count($keys) > 0 ?
                        $label['labels'][$keys[0]] : '';
            }
            $label['edit'] = $this->getLink("edit-label/{$label['id']}/");
            $label['delete'] = $this->getLink("{$label['id']}/",
                    'deleteLabel');
        }
        $params = array('labelsLabel' => $this->lang('labelsList'),
                'addLabelLink' => $this->getLink('add-label/'),
                'addLabelTitle' => $this->lang('addLabelTitle'),
                'addLabel' => $this->lang('addLabel'), 'labels' => $labels,
                'edit' => $this->lang('edit'), 'delete' =>
                $this->lang('delete'));
        $this->template('labels', $params);
    }

    /**
     * Returns names of sections defined in theme. These must be defined
     * directly in page.tpl.
     *
     * @param String $theme Theme name.
     * @return Array Names of defined sections.
     */
    private function getThemeSections($theme) {
        if (!file_exists(Config::ROOT . '/themes/' . $theme .
                '/templates/page.tpl')) {
            return array();
        }
        $template = file_get_contents(Config::ROOT . '/themes/' . $theme .
                '/templates/page.tpl');
        $sections = array();
        $chunks = preg_split('/\\{displaySection /', $template);
        foreach ($chunks as $chunk) {
            if (strpos($chunk, 'param=') !== false) {
                $sections[] = preg_replace('/^[^}]*param="([^"]*)".*$/', '\\1',
                        str_replace("\n", '', $chunk));
            }
        }
        return $sections;
    }

    /**
     * Determines whether the sections of theme defines an admin theme.
     *
     * @param Array $sections Names of sections defined in the theme.
     * @return boolean True if the theme is an admin theme.
     */
    private function isAdminTheme($sections) {
        $sections = array_fill_keys($sections, true);
        return (count($sections) == 4) && isset($sections['logout']) &&
                isset($sections['logout']) && isset($sections['submenu']) &&
                isset($sections['content']);
    }

    /**
     * Displays module administration interface for edditing module settings.
     *
     */
    private function displayAdminSettings() {
        if (!Modules::getModule('Users')->checkRights('View',
                'edit main settings')) {
            return;
        }
        $fileCategories = &Modules::getModule('Files')->getCategories();
        $themes = &$this->getThemes();
        foreach ($themes as &$theme) {
            $sections = $this->getThemeSections($theme);
            $theme = array('name' => $theme, 'isAdmin' =>
                    $this->isAdminTheme($sections));
        }
        $params = array('settings' => $this->lang('settingsForm'),
                'activePublicThemeLabel' => $this->lang('activePublicTheme'),
                'themes' => $themes, 'publicTheme' => $this->activeTheme,
                'activeAdminThemeLabel' => $this->lang('activeAdminTheme'),
                'adminTheme' => $this->activeAdminTheme, 'pageTitleLabel' =>
                $this->lang('pageTitleDefault'), 'pageKeywordsLabel' =>
                $this->lang('pageKeywordsDefault'), 'pageDescriptionLabel' =>
                $this->lang('pageDescriptionDefault'), 'pageRobotsLabel' =>
                $this->lang('pageRobotsDefault'), 'pageAuthorLabel' =>
                $this->lang('pageAuthorDefault'), 'pageCopyrightLabel' =>
                $this->lang('pageCopyrightDefault'), 'pageGeneratorLabel' =>
                $this->lang('pageGeneratorDefault'), 'save' =>
                $this->lang('save'), 'formStart' => $this->getForm('settings',
                true, 'View'), 'fileCategories' => $fileCategories,
                'filesRoot' => $this->filesRoot);
        $this->template('settings', $params);
    }

    /**
     * Displays module admin submenu.
     *
     */
    private function displayModuleAdminSubmenu() {
        if (!Modules::getModule('Users')->checkRights('View', 'view admin')) {
            return;
        }
        $params = array('menu' => array(array('href' => $this->getLink(),
                'title' => $this->lang('pagesTitle'),
                'label' => $this->lang('pages')), array('href' =>
                $this->getLink('custom-templates/'), 'title' =>
                $this->lang('customTemplatesTitle'), 'label' =>
                $this->lang('customTemplates')), array('href' =>
                $this->getLink('menus/'), 'title' => $this->lang('menusTitle'),
                'label' => $this->lang('menus')), array('href' =>
                $this->getLink('labels/'), 'title' => $this->lang(
                'labelsTitle'), 'label' => $this->lang('labels')), array(
                'href' => $this->getLink('settings/'), 'title' =>
                $this->lang('settingsTitle'), 'label' => $this->lang(
                'settings'))));
        $this->template('submenu', $params);
    }

    /**
     * Displays system admin interface.
     *
     * @param mixed $param Display parameter.
     */
    private function displayAdmin($param) {
        if (Kernel::isAJAXMode()) {
            $param = $_GET['section'];
        }
        if ($this->displayingContent && ($param !== 'logout')) {
            $this->displayModuleAdmin();
            return;
        }
        switch ($param) {
            case null:
                $this->template('page');
                break;
            case 'mainmenu':
                $modules = &$this->getAdminModuleList();
                $params = array('menu' => $modules);
                $this->template('mainmenu', $params);
                break;
            case 'submenu':
                if ($this->displayingSubmenu) {
                    $this->displayModuleAdminSubmenu();
                    return;
                }
                $details = $this->getUrl();
                if (count($details) > 0) {
                    $module = Modules::resolveModuleUrl($details[0]);
                    $module = Modules::getModule($module);
                    if ($module != null) {
                        $this->displayingSubmenu = true;
                        $module->display('submenu');
                    }
                }
                break;
            case 'content':
                if (Modules::getModule('Users')->checkRights('Users',
                        '_view admin')) {
                    $details = $this->getUrl();
                    $module = isset($details[0]) ?
                            Modules::resolveModuleUrl($details[0]) : null;
                    $module = Modules::getModule($module);
                    if ($module != null) {
                        $this->displayingContent = true;
                        $module->display();
                    }
                } else {
                    Modules::getModule('Users')->display();
                }
                break;
            case 'logout':
                if (Modules::getModule('Users')->checkRights('Users',
                        '_view admin')) {
                    Modules::getModule('Users')->display('logout');
                }
                break;
        }
    }

    /**
     * Returns list of modules available in administration interface for
     * current user.
     *
     * @return Array List of available modules.
     */
    private function &getAdminModuleList() {
        $modules = Modules::getModuleList();
        $menu = array();
        $url = $this->getUrl();
        $currentModuleUrl = '/admin/' . (isset($url[0]) ? "{$url[0]}/" : '');
        foreach ($modules as $module) {
            $details = Modules::getModuleDetails($module);
            if (!$details['installed'] || !$details['administrable']) {
                continue;
            }
            if (!Modules::getModule('Users')->checkRights($module,
                    'view admin')) {
                continue;
            }
            $menu[] = array('href' => Modules::getModule($module)->getLink(),
                    'title' => Modules::getModule($module)->getDescription(),
                    'label' => Modules::getModule($module)->getUIName(),
                    'active' => $currentModuleUrl ==
                    Modules::getModule($module)->getLink());
        }
        return $menu;
    }

    /**
     * Returns array of localized globaly used labels, that may be managed
     * through the administration interface.
     *
     * @return Array Localized global label.
     */
    private function &getGlobalLabels() {
        $records = &$this->dbapi->load($this->labelsRecord);
        $labels = array();
        foreach ($records as &$label) {
            $label['data']['labels'] = unserialize($label['data']['labels']);
            if (isset($label['data']['labels'][Kernel::getLanguage()])) {
                $lbl = $label['data']['labels'][Kernel::getLanguage()];
            } elseif (isset($label['data']['labels'][Config::DEFAULT_LANG])) {
                $lbl = $label['data']['labels'][Config::DEFAULT_LANG];
            } else {
                $keys = array_keys($label['data']['labels']);
                $lbl = count($keys) > 0 ? $label['data']['labels'][$keys[0]] :
                        '';
            }
            $labels[$label['data']['id']] = $lbl;
        }
        return $labels;
    }

    /**
     * Loads module settings from settings file.
     *
     */
    private function loadSettings() {
        if (!file_exists($this->getDir('/settings'))) {
            return;
        }
        $settings = unserialize(file_get_contents($this->getDir('/settings')));
        $this->activeTheme = $settings['activeTheme'];
        $this->activeAdminTheme = $settings['activeAdminTheme'];
        $this->pageTitle = $settings['pageTitle'];
        $this->pageKeywords = $settings['pageKeywords'];
        $this->pageDescription = $settings['pageDescription'];
        $this->pageRobots = $settings['pageRobots'];
        $this->pageAuthor = $settings['pageAuthor'];
        $this->pageCopyright = $settings['pageCopyright'];
        $this->pageGenerator = $settings['pageGenerator'];
        $this->filesRoot = $settings['filesRoot'];
    }

    /**
     * Sets up SMARTY instance.
     *
     */
    private function setUpSmarty() {
        if (!is_writable(Config::ROOT . '/cache/smarty')) {
            FTP::chmod('/cache/smarty');
        }
        if (!class_exists('Smarty')) {
            require Config::ROOT . '/libs/smarty/Smarty.class.php';
        }
        $this->smarty = new Smarty();
        $this->smarty->template_dir = Config::ROOT;
        $this->smarty->compile_dir = Config::ROOT . '/cache/smarty';
        $this->smarty->config_dir = Config::ROOT . '/libs/smarty/configs';
        $this->smarty->plugins_dir = array(Config::ROOT .
                '/libs/smarty/plugins');
    }

    /**
     * Loads modules to be displayed and initialize them for displaying
     * content.
     *
     */
    private function loadActiveModules() {
        if (Kernel::getMode() == Kernel::ADMIN) {
            $details = $this->getUrl();
            if (count($details) > 0) {
                $module = Modules::resolveModuleUrl($details[0]);
                Modules::getModule($module)->initDisplay();
            }
            if (!Modules::getModule('Users')->checkRights('Users',
                        '_view admin')) {
                Modules::getModule('Users')->initDisplay();
            }
        }
    }

    private function createLabels() {
        $locales = $this->getDetails();
        $locales = $locales['localization'];
        $labelNames = array('timerunout', 'autoLogout', 'refresh', 'user');
        $labelsRecs = array();
        $lang = array();
        foreach ($labelNames as $name) {
            $labelsRecs[$name] = $this->labelsRecord;
            $labelsRecs[$name]['data']['id'] = $name;
            $labelsRecs[$name]['data']['labels'] = array();
        }
        foreach ($locales as $locale) {
            require $this->getDir('/lang/' . $locale . '.php');
            foreach ($labelNames as $name) {
                $labelsRecs[$name]['data']['labels'][$locale] = $lang[$name];
            }
        }
        foreach ($labelsRecs as $rec) {
            $rec['data']['labels'] = serialize($rec['data']['labels']);
            $this->dbapi->save($rec);
        }
    }
}
?>
